# -*- coding:utf-8 -*-

import requests
from lxml import etree
from fake_useragent import UserAgent
from http import cookiejar
import json
from datetime import datetime
import time
import re
import csv


requests.packages.urllib3.disable_warnings()  # 忽略HTTPS安全警告


"""
B站 搜索获取视频信息、根据用户id获取关注数量、粉丝数量、播放数量、阅读数量
https://www.bilibili.com/v/fashion/makeup/?spm_id_from=333.6.b_7375626e6176.2#/206043/click/1/1/2020-04-19,2020-04-26
aid、bvid互转接口并可提取视频信息
https://api.bilibili.com/x/web-interface/view?aid=
https://api.bilibili.com/x/web-interface/view?bvid=
"""


class BililiUser():
    def __init__(self):
        #声明一个CookieJar对象实例来保存cookie
        # requests.utils.dict_from_cookiejar(html.cookies)  # 获取cookies转dict
        self.cookie = cookiejar.CookieJar()
        # ua = UserAgent(use_cache_server=False)  # 禁用服务器缓存
        self.headers = {
            # 'User-Agent': ua.random,
            # 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1 Safari/605.1.15',
            'authority': 's.search.bilibili.com',
            'method': 'GET',
            # 'path': '/cate/search?callback=jqueryCallback_bili_8592003274801652&main_ver=v3&search_type=video&view_type=hot_rank&order=click&copy_right=1&cate_id=157&page=2&pagesize=20&jsonp=jsonp&time_from=20200419&time_to=20200426&keyword=%E6%8A%A4%E8%82%A4%E5%93%81&_=1587882975271',
            'scheme': 'https',
            'accept': '*/*',
            'accept-encoding': 'gzip, deflate, br',
            'accept-language': 'zh-CN,zh;q=0.9',
            # 'cookie': '_uuid=7A706B5E-70F7-30CF-D55A-E1CF183AD50559300infoc; buvid3=C439EE52-96A7-467A-A5CA-4EE2EB1A0805155810infoc',
            'dnt': '1',
            'referer': 'https://space.bilibili.com/188839285/video?tid=0&page=2&keyword=&order=pubdate',
            'sec-fetch-dest': 'script',
            'sec-fetch-mode': 'no-cors',
            'sec-fetch-site': 'same-site',
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36'

        }

    # 获取列表信息
    def get_contents(self, cursor):
        postData = {
            'callback': 'jqueryCallback_bili_8592003274801652',
            'main_ver': 'v3',
            'search_type': 'video',
            'view_type': 'hot_rank',
            'order': 'click',
            'copy_right': '1',
            'cate_id': '157',
            'page': cursor,#'2',
            'pagesize': '20',
            'jsonp': 'jsonp',
            'time_from': '20200419',
            'time_to': '20200426',
            'keyword': '护肤品',
            '_': int(time.time() * 1000)#'1587882975271'
        }
        url = f"https://s.search.bilibili.com/cate/search"
        html = HttpUtils.do_request("GET", url, self.headers, postData)
        str_json = html.text.replace(postData['callback'], "").replace("(", "").replace(")", "")
        data_json = json.loads(str_json)
        for d in data_json['result']:
            dict_data = dict()
            dict_data['mid'] = d['mid']  # 用户id
            dict_data['author'] = d['author']  # 用户名
            dict_data['title'] = d['title']  # 标题
            dict_data['description'] = d['description']  # 简介
            dict_data['aid'] = d['id']  # 视频aID
            dict_data['bvid'] = d['bvid']  # 视频bvID
            dict_data['play'] = d['play']  # 播放数量
            dict_data['duration'] = d['duration']  # 时长
            dict_data['pubdate'] = d['pubdate']  # 发布时间
            dict_data['video_review'] = d['video_review']  # 历史弹幕数量
            dict_data['review'] = d['review']  # 评论数量
            dict_data['tag'] = d['tag']  # 标签
            dict_data['arcurl'] = d['arcurl']  # 视频链接地址

            print(str(dict_data))
            # 获取视频信息投币枚数
            self.get_vido(dict_data['aid'], dict_data)
            # 获取关注数量、粉丝数量
            self.get_follower_following(dict_data['mid'], dict_data)
            # 获取播放数量、阅读数量
            self.get_play_read(dict_data['mid'], dict_data)
            # 通过页面，获取播放数、弹幕数、点赞数、投硬币枚数、收藏人数、分享
            # self.get_count(dict_data['bvid'], dict_data)

    # 获取列表信息-首页搜索
    def get_contents_top(self, cursor):
        postData = {
            'context':'',
            'page': cursor,
            'order':'',
            'keyword': '美妆设计',
            'duration':'',
            'tids_1':'',
            'tids_2':'',
            '__refresh__': 'true',
            '_extra':'',
            'search_type': 'video',
            'highlight': '1',
            'single_column': '0',
            'jsonp': 'jsonp',
            'callback': '__jp2'

        }
        url = f"https://api.bilibili.com/x/web-interface/search/type"
        html = HttpUtils.do_request("GET", url, self.headers, postData)
        str_json = html.text.replace(postData['callback'], "").replace("(", "").replace(")", "")
        data_json = json.loads(str_json)
        for d in data_json['data']['result']:
            dict_data = dict()
            dict_data['mid'] = d['mid']  # 用户id
            dict_data['author'] = d['author']  # 用户名
            dict_data['title'] = d['title']  # 标题
            dict_data['description'] = d['description']  # 简介
            dict_data['aid'] = d['id']  # 视频aID
            dict_data['bvid'] = d['bvid']  # 视频bvID
            dict_data['play'] = d['play']  # 播放数量
            dict_data['duration'] = d['duration']  # 时长
            dict_data['pubdate'] = d['pubdate']  # 发布时间
            dict_data['video_review'] = d['video_review']  # 历史弹幕数量
            dict_data['review'] = d['review']  # 评论数量
            dict_data['tag'] = d['tag']  # 标签
            dict_data['arcurl'] = d['arcurl']  # 视频链接地址

            print(str(dict_data))
            # # 获取视频信息投币枚数-aid
            # self.get_vido(dict_data['aid'], dict_data)
            # 获取视频信息投币枚数-bvid
            self.get_vido_bvid(dict_data['bvid'], dict_data)
            # 获取关注数量、粉丝数量
            self.get_follower_following(dict_data['mid'], dict_data)
            # 获取播放数量、阅读数量
            self.get_play_read(dict_data['mid'], dict_data)


    # 根据aid获取视频信息-接口1
    def get_vido(self, aid, dict_data):
        url = f"https://api.bilibili.com/x/web-interface/archive/stat?aid={aid}"
        html = HttpUtils.do_request("GET", url, self.headers, "")
        data_json = json.loads(html.text)
        dict_data['like'] = data_json['data']['like']  # 获赞数量
        dict_data['coin'] = data_json['data']['coin']  # 投币枚数
        dict_data['favorite'] = data_json['data']['favorite']  # 收藏数量
        dict_data['share'] = data_json['data']['share']  # 分享数量
        dict_data['view'] = data_json['data']['view']  # 播放数量
        dict_data['danmaku'] = data_json['data']['danmaku']  # 实时弹幕数量
        dict_data['reply'] = data_json['data']['reply']  # 评论数量
        print(f"============获取用户：{aid} 视频信息=============")


    # 根据aid获取视频信息-接口2
    def get_vido_aid(self, aid, dict_data):
        url = f"https://api.bilibili.com/x/web-interface/view?aid={aid}"
        html = HttpUtils.do_request("GET", url, self.headers, "")
        data_json = json.loads(html.text)
        dict_data['like'] = data_json['data']['stat']['like']  # 获赞数量
        dict_data['coin'] = data_json['data']['stat']['coin']  # 投币枚数
        dict_data['favorite'] = data_json['data']['stat']['favorite']  # 收藏数量
        dict_data['share'] = data_json['data']['stat']['share']  # 分享数量
        dict_data['view'] = data_json['data']['stat']['view']  # 播放数量
        dict_data['danmaku'] = data_json['data']['stat']['danmaku']  # 实时弹幕数量
        dict_data['reply'] = data_json['data']['stat']['reply']  # 评论数量
        print(f"============获取用户：{aid} 视频信息=============")


    # 根据bvid获取视频信息
    def get_vido_bvid(self, bvid, dict_data):
        url = f"https://api.bilibili.com/x/web-interface/view?bvid={bvid}"
        html = HttpUtils.do_request("GET", url, self.headers, "")
        data_json = json.loads(html.text)
        dict_data['like'] = data_json['data']['stat']['like']  # 获赞数量
        dict_data['coin'] = data_json['data']['stat']['coin']  # 投币枚数
        dict_data['favorite'] = data_json['data']['stat']['favorite']  # 收藏数量
        dict_data['share'] = data_json['data']['stat']['share']  # 分享数量
        dict_data['view'] = data_json['data']['stat']['view']  # 播放数量
        dict_data['danmaku'] = data_json['data']['stat']['danmaku']  # 实时弹幕数量
        dict_data['reply'] = data_json['data']['stat']['reply']  # 评论数量
        print(f"============获取用户：{bvid} 视频信息=============")




    # 根据用户id获取：关注数量、粉丝数量
    def get_follower_following(self, mid, dict_data):
        url = f"https://api.bilibili.com/x/relation/stat?vmid={mid}&jsonp=jsonp&callback=__jp3"
        html = HttpUtils.do_request("GET", url, self.headers, "")
        str_json = html.text.replace("__jp3(", "").replace(")", "")
        data_json = json.loads(str_json)
        dict_data['follower'] = data_json['data']['follower']  # 关注数量
        dict_data['following'] = data_json['data']['following']  # 粉丝数量
        print(f"============获取用户：{mid} 关注数量、粉丝数量=============")



    # 根据用户id获取：播放数量、阅读数量
    def get_play_read(self, mid, dict_data):
        url = f"https://api.bilibili.com/x/space/upstat?mid={mid}&jsonp=jsonp&callback=__jp4"
        html = HttpUtils.do_request("GET", url, self.headers, "")
        str_json = html.text.replace("__jp4(", "").replace(")", "")
        data_json = json.loads(str_json)
        dict_data['likes'] = data_json['data']['likes']  # 获赞数量
        dict_data['play_count'] = data_json['data']['archive']['view']  # 播放数量
        dict_data['read_count'] = data_json['data']['article']['view']  # 阅读数量
        print(f"============获取用户：{mid} 播放数量、阅读数量=============")


    # 根据用户mid查询视频信息
    def get_video_info(self, mid, current):
        postData = {
            'mid': mid,
            'ps': '30',
            'tid': '0',
            'pn': current,
            'keyword':'',
            'order': 'pubdate',
            'jsonp': 'jsonp'
        }
        url = "https://api.bilibili.com/x/space/arc/search"
        html = HttpUtils.do_request("GET", url, self.headers, postData)
        data_json = json.loads(html.text)
        count = data_json['data']['page']['count']
        for d in data_json['data']['list']['vlist']:
            dict_data = dict()
            dict_data['mid'] = d['mid']  # 用户id
            dict_data['author'] = d['author']  # 用户名
            dict_data['aid'] = d['aid']  # 视频aid
            dict_data['bvid'] = d['bvid']  # 视频bvid
            dict_data['title'] = d['title']  # 视频标题
            dict_data['comment'] = d['comment']  # 评论数量
            dict_data['description'] = d['description']  # 简介
            dict_data['length'] = d['length']  # 视频时长
            dict_data['play'] = d['play']  # 播放数量
            dict_data['video_review'] = d['video_review']  # 历史弹幕数量
            print(str(dict_data))
        if current * 30 < count:
            self.get_video_info(mid, current + 1)


    # 通过页面，获取播放数、弹幕数、点赞数、投硬币枚数、收藏人数、分享
    def get_count(self, bvid, dict_data):
        result = 0
        print("========获取获赞数量========")
        url = f"https://www.bilibili.com/video/{bvid}"
        html = requests.get(url, headers=self.headers, verify=False)
        root = etree.HTML(html.text)
        if html.status_code == 200:
            if len(root.xpath('//span[@class="view"]')) > 0:
                # 具体数字
                # dict_data['总播放数'] = root.xpath('//span[@class="view"]/@title')[0].replace("总播放数", "")
                # dict_data['历史累计弹幕数'] = root.xpath('//span[@class="dm"]/@title')[0].replace("历史累计弹幕数", "")
                # dict_data['点赞数'] = root.xpath('//span[@class="like"]/@title')[0].replace("点赞数", "")
                # 无具体数字
                dict_data['总播放数'] = "".join(root.xpath('//span[@class="view"]//text()')).replace("播放 ·", "").replace("\n", "").strip()
                dict_data['历史累计弹幕数'] = "".join(root.xpath('//span[@class="dm"]//text()')).replace("弹幕", "").replace("\n", "").strip()
                dict_data['点赞数'] = "".join(root.xpath('//span[@class="like"]//text()')).replace("点赞", "").replace("\n", "").strip()
                dict_data['投硬币枚数'] = "".join(root.xpath('//span[@class="coin"]//text()')).replace("投币", "").replace("\n", "").strip()
                dict_data['收藏人数'] = "".join(root.xpath('//span[@class="collect"]//text()')).replace("--", "").replace("收藏", "").replace("\n", "").strip()
                dict_data['分享'] = "".join(root.xpath('//span[@class="share"]//text()')).replace("分享", "").replace("\n", "").strip()
                # 格式化数据
                if dict_data['总播放数'].find("万") < 0:
                    dict_data['总播放数'] = str(int(dict_data['总播放数']) / 10000) + "万"
                if dict_data['历史累计弹幕数'].find("万") < 0:
                    if len(dict_data['历史累计弹幕数']) == 0:
                        dict_data['历史累计弹幕数'] = 0
                    dict_data['历史累计弹幕数'] = str(int(dict_data['历史累计弹幕数']) / 10000) + "万"
                if dict_data['点赞数'].find("万") < 0:
                    if len(dict_data['点赞数']) == 0:
                        dict_data['点赞数'] = 0
                    dict_data['点赞数'] = str(int(dict_data['点赞数']) / 10000) + "万"
                if dict_data['投硬币枚数'].find("万") < 0:
                    if len(dict_data['投硬币枚数']) == 0:
                        dict_data['投硬币枚数'] = 0
                    dict_data['投硬币枚数'] = str(int(dict_data['投硬币枚数']) / 10000) + "万"
                if dict_data['收藏人数'].find("万") < 0:
                    if len(dict_data['收藏人数']) == 0:
                        dict_data['收藏人数'] = 0
                    dict_data['收藏人数'] = str(int(dict_data['收藏人数']) / 10000) + "万"
                if dict_data['分享'].find("万") < 0:
                    if len(dict_data['分享']) == 0:
                        dict_data['分享'] = 0
                    dict_data['分享'] = str(int(dict_data['分享']) / 10000) + "万"

        elif html.status_code == 412:
            print("===========请求被拦截============")
            result = 1

        return result


    def get_comments(self, oid, current):
        postData = {
            'callback': 'jQuery17206552688840189551_1614228188579',
            'jsonp': 'jsonp',
            'pn': current,
            'type': '1',
            'oid': '971811917',
            'sort': '2',
            '_': int(time.time() * 1000)
        }

        url = "https://api.bilibili.com/x/v2/reply"
        res = HttpUtils.do_request("GET", url ,self.headers, postData)
        json_data = res.text.replace(postData['callback'], "").replace('(', "").replace(")", "")
        json_data = json.loads(json_data)
        for d in json_data['data']['replies']:
            dict_data = dict()
            dict_data['评论'] = d['content']['message']
            dict_data['用户名'] = d['member']['uname']
            dict_data['用户mid'] = d['member']['mid']
            dict_data['用户简介'] = d['member']['sign']
            dict_data['用户性别'] = d['member']['sex']
            if d.get('level_info') is not None:
                dict_data['用户等级'] = d['level_info']['current_level']
            dict_data['发布时间'] = datetime.fromtimestamp(int(d['ctime'])).strftime("%Y-%m-%d %H:%M:%S")
            dict_data['点赞数'] = d['like']
            print(str(dict_data))


if __name__ == '__main__':
    buser = BililiUser()
    # # 根据用户mid查询所有视频信息
    # buser.get_video_info("546195", 1)

    # # 根据aid获取视频信息-接口1
    # buser.get_vido("795138286",dict())

    # # 根据aid获取视频信息-接口2
    # buser.get_vido_aid("795138286",dict())

    # 根据bvid获取视频信息
    # buser.get_vido_bvid("BV1g5411x7Ep",dict())

    # 通过页面，获取播放数、弹幕数、点赞数、投硬币枚数、收藏人数、分享
    # buser.get_count('BV1g5411x7Ep', dict())

    # 获取评论内容
    # buser.get_comments("971811917", "1")

    for i in range(1, 401):
        print(f"============第{i}页=============")
        buser.get_contents(i)
        # # 使用首页搜索入口
        # buser.get_contents_top(i)


